﻿// Autore: Alessio Parma

using System;
using System.Collections.Generic;
using System.Data.Objects.DataClasses;

namespace RecipesManager.Data.Implementation
{
    sealed partial class Category : ICategory
    {
        readonly ILink<ICategory> _children;
        readonly ILink<IIngredient> _ingredients;
        readonly ILink<ICategory> _parent;

        public Category()
        {
            _children = new CategoryEntities(() => Children);
            _ingredients = new IngredientEntities(() => Ingredients);
            _parent = new CategoryEntities(() => Parents);
        }

        #region ICategory Members

        string INamedEntity.Name
        {
            get { return Name; }
        }

        ILink<ICategory> ICategory.Children
        {
            get { return _children; }
        }

        IEnumerable<IGuest> ICategory.GuestIntolerances
        {
            get { return GuestIntolerances; }
        }

        IEnumerable<IOtherRating<IGuest, FoodRating>> ICategory.GuestRatings
        {
            get { return GuestRatings; }
        }

        ILink<IIngredient> ICategory.Ingredients
        {
            get { return _ingredients; }
        }

        ILink<ICategory> ICategory.Parents
        {
            get { return _parent; }
        }

        public bool Equals(ICategory other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return Id == other.Id;
        }

        public void Update(string name)
        {
            Name = name.ToKey();
            Manager.SaveChanges();
        }

        #endregion

        public static Category New(string name)
        {
            name = name.ToKey();
            return CreateCategory(0, name);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            return ReferenceEquals(this, obj) || Equals(obj as ICategory);
        }

        public override int GetHashCode()
        {
            return Id;
        }

        public override string ToString()
        {
            return string.Format("Category(Name: {0})", Name);
        }
    }

    sealed class CategoryObjects : NamedObjects<Category, ICategory>, ICategories
    {
        public CategoryObjects() : base(Manager.CategorySet)
        {
        }

        #region ICategories Members

        public ICategory Add(string name)
        {
            return Add(Category.New(name));
        }

        #endregion
    }

    sealed class CategoryEntities : NamedEntities<Category, ICategory>, ILink<ICategory>
    {
        public CategoryEntities(Func<EntityCollection<Category>> items) : base(items, Manager.CategorySet)
        {
        }

        #region ILink<ICategory> Members

        public INamedEntities<ICategory> Entities
        {
            get { return Manager.Categories; }
        }

        public ICategory Add(string name)
        {
            return AddName(name);
        }

        #endregion
    }

    sealed partial class CategoryGuestRating : IRating<ICategory, FoodRating>, IOtherRating<IGuest, FoodRating>
    {
        #region IOtherRating<IGuest,FoodRating> Members

        IGuest IOtherRating<IGuest, FoodRating>.Entity
        {
            get { return Guest; }
        }

        int IOtherRating<IGuest, FoodRating>.Id
        {
            get { return GuestId; }
        }

        string IOtherRating<IGuest, FoodRating>.Name
        {
            get { return Guest.Name; }
        }

        FoodRating IOtherRating<IGuest, FoodRating>.Rating
        {
            get { return (FoodRating) Rating; }
        }

        #endregion

        #region IRating<ICategory,FoodRating> Members

        ICategory IRating<ICategory, FoodRating>.Entity
        {
            get { return Category; }
        }

        int IEntity.Id
        {
            get { return CategoryId; }
        }

        string INamedEntity.Name
        {
            get { return Category.Name; }
        }

        FoodRating IRating<ICategory, FoodRating>.Rating
        {
            get { return (FoodRating) Rating; }
        }

        public void Update(FoodRating rating)
        {
            Rating = (byte) rating;
            Manager.SaveChanges();
        }

        #endregion
    }

    sealed class CategoryRatings : NamedLinkSet<CategoryGuestRating, IRating<ICategory, FoodRating>>,
                                   IRatings<ICategory, FoodRating>
    {
        public CategoryRatings(Func<EntityCollection<CategoryGuestRating>> items, Func<int> idGetter)
            : base(items, idGetter)
        {
        }

        #region IRatings<ICategory,FoodRating> Members

        public INamedEntities<ICategory> Entities
        {
            get { return Manager.Categories; }
        }

        public IRating<ICategory, FoodRating> Add(string name, FoodRating rating)
        {
            return Add(CategoryGuestRating.CreateCategoryGuestRating(IdGetter(), Entities[name].Id, (byte) rating));
        }

        #endregion
    }
}